#ifndef __M_CONNECTION_H__
#define __M_CONNECTION_H__

#include"mq_channel.hpp"

namespace mq{
    
    class Connection{
        public:
        using ptr = std::shared_ptr<Connection>;
        Connection(const ConsumerManager::ptr& consumerManagerP,
            const muduo::net::TcpConnectionPtr& connP,
            const ProtobufCodecPtr& codecP,
            const Virtualhost::ptr& vHost,
            const ThreadPool::ptr& pool):
            _consumerManagerP(consumerManagerP),
            _connectionP(connP),
            _codecP(codecP),
            _vHost(vHost),
            _pool(pool),
            _channelManager(std::make_shared<ChannelManager>()){}

        ~Connection(){}

        void openChannel(const openChannelRequestPtr& req){
            int ret = _channelManager->openChannel(req->cid(),_consumerManagerP,_connectionP,_codecP,_vHost,_pool);
            if(ret == false){
                return basicResponse(ret,req->rid(),req->cid());
            }
            return basicResponse(ret,req->rid(),req->cid());
        }
        void closeChannel(const closeChannelRequestPtr& req){
            _channelManager->closeChannel(req->cid());
            return basicResponse(true,req->rid(),req->cid());
        }

        Channel::ptr getChannel(const std::string& cid){
            Channel::ptr cp = _channelManager->getChannel(cid);
            return cp;
        }

        private:
            void basicResponse(bool ok,std::string rid,std::string cid){
                basicCommonResponse rep;
                rep.set_ok(ok);
                rep.set_rid(rid);
                rep.set_cid(cid);
                _codecP->send(_connectionP,rep);
            }
        private:
            ConsumerManager::ptr _consumerManagerP;
            muduo::net::TcpConnectionPtr _connectionP;
            ProtobufCodecPtr _codecP;
            Virtualhost::ptr _vHost;
            ThreadPool::ptr _pool;
            ChannelManager::ptr _channelManager;
    };

    class ConnectionManager{
        public:

            using ptr = std::shared_ptr<ConnectionManager>;
            ConnectionManager(){
                LOG_DEBUGM("Channel init...");

            }
            
            void openConnection(const ConsumerManager::ptr& consumerManagerP,
            const muduo::net::TcpConnectionPtr& connP,
            const ProtobufCodecPtr& codecP,
            const Virtualhost::ptr& vHost,
            const ThreadPool::ptr& pool){
                std::unique_lock<std::mutex> _mutex;
                auto it = _manager.find(connP);
                if(it != _manager.end()){
                    return;
                }
                Connection::ptr cp = std::make_shared<Connection>(consumerManagerP,connP,codecP,vHost,pool);
                _manager.insert(std::make_pair(connP,cp));
            }

            void closeConnection(const muduo::net::TcpConnectionPtr& conn){
                std::unique_lock<std::mutex> _mutex;
                _manager.erase(conn);
            }

            Connection::ptr getConnection(const muduo::net::TcpConnectionPtr& conn){
                std::unique_lock<std::mutex> _mutex;
                auto it = _manager.find(conn);
                if(it == _manager.end()){
                    return Connection::ptr();
                }
                return it->second;
            }
        private:
            std::mutex _mutex;
            std::unordered_map<muduo::net::TcpConnectionPtr,Connection::ptr> _manager;
    };
    
}

#endif